<?php

    /**
     * Form helper class
     * 
     * TODO: write detailed documentation
     *
     * @version 3.0
	 * @package Helpers
     * @author Anton Perkin
     *
     */
    class FormHelper
    {

		/* CONSTRUCTORS */
        
		/**
		 * Default constructor
		 *
		 * @param object $data data and metadata
		 * @param array $options form options
		 */
		function __construct($data = '', $options = array())
    	{	
    		//includes related files
            require_once 'htmlEnums.php';
            require_once 'htmlForm.php';
            
			//form id            
            $this->id = mt_rand();
            
            //sets options
            foreach ($options as $optionName => $optionValue)
            {
            	$this->$optionName = $this->optionValue;
            }
            
            //if data + metadata provided
            if (!empty($data))
            {
            	$this->ParseFormData($data);
            }
            
            //jquery helper initialization
            include_once(strtolower(SYSTEM_HELPERS.'jquery.php'));
//            jQueryHelper::Initialize();
    	}
        
    	
        /* FIELDS */
        
    	/**
    	 * Form contents
    	 * @var string
    	 */
    	private $contentString = '';

    	/**
    	 * Form toolbar
    	 * @var string
    	 */
    	private $toolbarString = '';

    	/**
    	 * Form header
    	 * @var string
    	 */
       	private $headerString = '';

    	/**
    	 * Form footer
    	 * @var string
    	 */
    	private $footerString = '';

    	/**
    	 * Form message
    	 * @var string
    	 */
    	private $messageString = '';
    	
    	/**
    	 * Form text
    	 * @var string
    	 */
    	private $textString = '';

    	/**
    	 * Form error
    	 * @var string
    	 */
    	private $errorString = '';

    	/**
    	 * Form start
    	 * @var string
    	 */
    	private $createString = '';

    	/**
    	 * Form end
    	 * @var string
    	 */
    	private $endString = '</form>';

    	/**
    	 * Form internal identifier
    	 *
    	 * @var string
    	 */
    	private $id = null;
    	
    	/**
    	 * Form data
    	 *
    	 * @var array
    	 */
    	private $data = array();

    	/**
    	 * Form fields' errors
    	 *
    	 * @var array
    	 */
    	public $errors = array();
    	
    	/**
    	 * Form meta data
    	 *
    	 * @var array
    	 */
    	private $metaData = array();

    	/**
    	 * Form elements (fields)
    	 * @var array
    	 */
    	private $elements = array();

    	/**
    	 * Form attributes
    	 * @var array
    	 */
    	private $formAttributes = array();

    	/**
    	 * Form readonly elements
    	 * @var array
    	 */
    	private $readonlyElements = array();

    	/**
    	 * Form disabled elements
    	 * @var array
    	 */
    	private $disabledElements = array();

    	/**
    	 * Enables/disables multi-language support
    	 * 
    	 * @var boolean
    	 */
    	private $multiLanguage = true;

		/**
		 * form template
		 * 
		 * @var string
		 */
		private $template = '{toolbar}<div class = "form">{header}{message}{error}{form}{footer}</div>';

		/**
		 * default field block template
		 * 
		 * @var string
		 */
		private $elementTemplate = '<div class = "formElement">{before}<label class = "label">{label}</label>{between}{field} <span class = "formElementComment">{comment}</span> <span class = "formElementError">{error}</span>{after}</div>';

		/**
		 * default button block template
		 * 
		 * @var string
		 */
		private $buttonTemplate = '{before}{field} {after}';
		
		/**
		 * form header template
		 * 
		 * @var string
		 */
		private $headerTemplate = '<div class = "formHeader">{header}<span class = "formHeaderMessagePlaceholder"></span></div>';

		/**
		 * form footer template
		 * 
		 * @var string
		 */
		private $footerTemplate = '<div class = "formFooter">{footer}</div>';

		/**
		 * form message template
		 * 
		 * @var string
		 */
		private $messageTemplate = '<div class = "formMessage" >{message}</div>';

		/**
		 * form message error
		 * 
		 * @var string
		 */
		private $errorTemplate = '<div class = "formError">{error}</div>';

		/**
		 * Allowed insets for the form element template
		 * @var array
		 */
		private $allowedInsets = array('before', 'between', 'after');

		/**
		 * Object primary key
		 *
		 * @var array
		 */
		private $primaryKey = array();
		
		/**
		 * Enables/disables form submit
		 *
		 * @var boolean
		 */
		private $disabled = false;
		
		
        /* CSS CLASSES */

		/**
		 * form element CSS class
		 * @var string
		 */
		public $elementClass = 'formElement';
		
		/**
		 * label CSS class
		 * @var string
		 */
		public $labelClass = 'label';
		
		/**
		 * input text CSS class
		 * @var string
		 */
		public $inputTextClass = 'text';

		/**
		 * input hidden CSS class
		 * @var string
		 */
		public $inputHiddenClass = '';
		
		/**
		 * checkbox CSS class
		 * @var string
		 */
		public $inputCheckboxClass = 'checkbox';
		
		/**
		 * select CSS class
		 * @var string
		 */
		public $selectClass = 'select';
		
		/**
		 * password CSS class
		 * @var string
		 */
		public $inputPasswordClass = 'text';
		
		/**
		 * textarea CSS class
		 * @var string
		 */
		public $textareaClass = 'textarea';
    	
		/**
		 * submit button CSS class
		 * @var string
		 */
		public $inputSubmitClass = 'submit';

		/**
		 * reset button CSS class
		 * @var string
		 */
		public $inputResetClass = 'submit';
		
		/**
		 * button CSS class
		 * @var string
		 */
		public $inputButtonClass = 'submit';
		
		/**
		 * submit image button CSS class
		 * @var string
		 */
		public $inputImageClass = 'submit';
		
		
    	/* PROPERTIES */
    	
        /**
		 * @return the $id form id
		*/
		public function getId ()
		{
			return $this->id;
		}		
		
        /**
    	 * @return the $multiLanguage
    	 */
    	public function getMultiLanguage ()
    	{
    		return $this->multiLanguage;
    	}
    
    	/**
    	 * @param boolean $multiLanguage
    	 */
    	public function setMultiLanguage ($multiLanguage)
    	{
    		$this->multiLanguage = $multiLanguage;
    	}    	
    	
        /**
         * @return the $template
         */
        public function getTemplate ()
        {
        	return $this->template;
        }
        
        /**
         * @param string $template
         */
        public function setTemplate ($template)
        {
        	$this->template = $template;
        }    	
    	
        /**
    	 * @return the $elementTemplate
    	 */
    	public function getElementTemplate ()
    	{
    		return $this->elementTemplate;
    	}
    
    	/**
    	 * @param string $elementTemplate
    	 */
    	public function setElementTemplate ($elementTemplate)
    	{
    		$this->elementTemplate = $elementTemplate;
    	}    	
    	
        /**
    	 * @return the $headerTemplate
    	 */
    	public function getHeaderTemplate ()
    	{
    		return $this->headerTemplate;
    	}
    
    	/**
    	 * @param string $headerTemplate
    	 */
    	public function setHeaderTemplate ($headerTemplate)
    	{
    		$this->headerTemplate = $headerTemplate;
    	}
    
    	/**
    	 * @return the $footerTemplate
    	 */
    	public function getFooterTemplate ()
    	{
    		return $this->footerTemplate;
    	}
    
    	/**
    	 * @param string $footerTemplate
    	 */
    	public function setFooterTemplate ($footerTemplate)
    	{
    		$this->footerTemplate = $footerTemplate;
    	}
    
    	/**
    	 * @return the $messageTemplate
    	 */
    	public function getMessageTemplate ()
    	{
    		return $this->messageTemplate;
    	}
    
    	/**
    	 * @param string $messageTemplate
    	 */
    	public function setMessageTemplate ($messageTemplate)
    	{
    		$this->messageTemplate = $messageTemplate;
    	}
    
    	/**
    	 * @return the $errorTemplate
    	 */
    	public function getErrorTemplate ()
    	{
    		return $this->errorTemplate;
    	}
    
    	/**
    	 * @param string $errorTemplate
    	 */
    	public function setErrorTemplate ($errorTemplate)
    	{
    		$this->errorTemplate = $errorTemplate;
    	}
	    	
	    /**
		 * @return the $disabled
		 */
		public function getDisabled ()
		{
			return $this->disabled;
		}
	
		/**
		 * @param boolean $disabled
		 */
		public function setDisabled ($disabled)
		{
			$this->disabled = $disabled;
		}

		/* PRIVATE METHODS */
    	
    	/**
    	 * Translates the text in case $this->multiLanguage = true
    	 * 
    	 * @param string $text text to translate
    	 */
    	private function Translate($text)
    	{
    	    if ($this->multiLanguage)
    	    {
    	        $modifier = (strtoupper($text) == $text) ? StringCaseType::Uppercase : ((ucfirst($text) == $text) ? StringCaseType::Capitalize : StringCaseType::None);
    	        return Language::Get(str_replace('_', ' ', $text), $modifier);
    	    }
    	    else
    	    {
    	        return $text;
    	    }
    	}
    	
		/**
		 * Gets field value
		 *
		 * @param string $name field name
		 * @param array $attributes field attributes
		 * @return string
		 */
    	private function GetFieldValue($name, $attributes)
    	{
    		$value = (isset($attributes['value'])) ? $attributes['value'] : ((isset($this->data->$name)) ? $this->data->$name : '');
    		
    		//date parse
    		if ((!empty($value)) && isset($this->metaData['properties'][$name]['column_type']) && ($this->metaData['properties'][$name]['column_type'] == ColumnType::Date))
    		{
   		 		$value = date(Config::$general['date_format'], strtotime($value));
       		}
       		
    		return $value;
    	}

		/**
		 * Gets field error
		 *
		 * @param string $name field name
		 * @return string
		 */
    	private function GetFieldError($name)
    	{
    		$errorMessage = '';
    		if (isset($this->errors[$name]))
    		{
    			foreach ($this->errors[$name] as $errorType => $errorValue)
    			{
    				$errorMessage .= $this->GetErrorMessage($errorType, $errorValue).'. ';
    			}
    		}
    		
    		return $errorMessage;
    	}
    	
    	/**
    	 * Gets the error message
    	 *
    	 * @param string $type error type
    	 * @param string $value error value
    	 * @return string
    	 */
    	public function GetErrorMessage($type, $value = '')
    	{
    		$errorMessage = Language::Get('Validation error '.$type, StringCaseType::Capitalize, array($value));
    		
    		return $errorMessage;
    	}    	
    	
    	/**
    	 * Gets field label
    	 *
    	 * @param string $name field name
    	 * @param string $label field label
    	 * @return string
    	 */
    	private function GetFieldLabel($name, $options)
    	{
	        $label = StringUtils::GetValue($options['label'], ucfirst($name));
	        $label = $this->Translate($label);
	        
	        //adds required (*) sign if needed
	        $label = ((isset($this->metaData['properties'])) && (isset($this->metaData['properties'][$name]['required'])) 
	        			&& ($this->metaData['properties'][$name]['required'] === true) 
	        			&& ((!isset($options['required'])) || (isset($options['required']) && ($options['required'] != false)))
	        			&& ($this->metaData['properties'][$name]['column_type'] != ColumnType::Boolean)) ? $label.'*' : $label;
       	
    		return $label;
    	}
    	
    	/**
    	 * Gets field id
    	 *
    	 * @param string $name field name
    	 * @param array $attributes field attributes
    	 * @return string
    	 */
    	private function GetFieldId($name, $attributes)
    	{
    		$result = str_replace('[', '', (isset($attributes['id'])) ? ($attributes['id']) : $this->id.'_'.$name);
    		$result = str_replace(']', '', $result);
    		return $result;
    	}
    	
    	/**
    	 * Adds an element to the current form
    	 * 
    	 * @param string $tag tag name
    	 * @param string $name field name
    	 * @param array $options field options
    	 * @param string $content tag content
    	 * @param array $attributes field attributes
    	 */
    	private function AddElement($tag, $name, $options = array(), $content = '', $attributes = array())
    	{
    	    //notice prevent
    	    $attributes['type'] = (!isset($attributes['type'])) ? '' : $attributes['type'];
    	    $attributes['class'] = (!isset($attributes['class'])) ? '' : $attributes['class'];
    	    
    	    //tag name
    	    $this->elements[$name]['tag'] = $tag;
    	    
    	    //tag value
    	    $this->elements[$name]['value'] = $this->GetFieldValue($name, $attributes);
    	    
    	    //html attributes
    	    $this->elements[$name]['attributes'] = $attributes;
    	    
    	    //tag id
    	    $this->elements[$name]['attributes']['id'] = $this->GetFieldId($name, $attributes);
    	    
    	    //css
    	    $className = $tag.ucfirst($attributes['type']).'Class';
    	    
    	    //tag value
    	    $this->elements[$name]['attributes']['class'] = StringUtils::GetValue($attributes['class'], $this->$className);
    	    
    	    //element block template
    	    $options['template'] = (empty($options['template'])) ? $this->elementTemplate : $options['template'];

    	    //element error
    	    $options['error'] = (empty($options['error'])) ? $this->GetFieldError($name) : $options['error'];

    	    //label
    	    $options['label'] = (!isset($options['label'])) ? '' : $options['label'];
    	    if ($options['label'] !== false)
    	    {
    	    	$options['label'] = $this->GetFieldLabel($name, $options);
    	    }
    	    else
    	    {
    	        $options['template'] = str_replace('<label class = "label">{label}</label>', '', $options['template']);
    	    }
    	    
    	    //template insets parsing
    	    foreach ($this->allowedInsets as $inset)
    	    {
    	        $options[$inset] = (isset($options[$inset])) ? $options[$inset] : '';
    	        $options['template'] = str_replace('{'.$inset.'}', $options[$inset], $options['template']);
    	    }
    	    
    	    //field block options
    	    if (!empty($options))
    	    {
        	    foreach ($options as $optionName => $optionValue)
        	    {
        	        $this->elements[$name]['options'][$optionName] = $optionValue;
        	    }
    	    }
    	}
    	
    	/**
    	 * Gets the full field block
    	 * 
    	 * @param string $name field name
    	 * @return string
    	 */
    	private function GetElementBlock($name)
    	{
    	    //common configuration
    	    $element = $this->elements[$name];
            $element['options']['field_attributes'] = $element['attributes'];
            $value = $element['value'];
            $label = $element['options']['label'];
            $options = $element['options'];
            $template = $element['options']['template'];
            
    	    ob_start();
    	    switch ($element['tag'])
    	    {
    	        case FormElement::Input:
    	            switch ($element['attributes']['type'])
    	            {
    	                case InputType::Text:
    	                    HtmlFormHelper::InputTextBlock($name, $value, $label, $options, $template);
    	                    break;
    	                case InputType::Hidden:
    	                    HtmlFormHelper::InputHidden($name, $value, $options['field_attributes']);
    	                    break;
    	                case InputType::Password:
    	                    HtmlFormHelper::InputPasswordBlock($name, $value, $label, $options, $template);
    	                    break;
    	                case InputType::Checkbox:
    	                    HtmlFormHelper::InputCheckboxBlock($name, $value, $label, 1, $options, $template);
    	                    break;
    	                case InputType::Submit: case InputType::Image: case InputType::Button: case InputType::Reset:
    	                    HtmlFormHelper::InputSubmitBlock($name, $value, $options, $template);
    	                    break;
    	            }
    	            break;
    	            
    	        case FormElement::Textarea:
                    HtmlFormHelper::TextareaBlock($name, $value, $label, $options, $template);
    	            break;
    	            
    	        case FormElement::Select:
    	            $selectOptions = (empty($options['options'])) ? array() : $options['options'];
                    HtmlFormHelper::SelectBlock($name, $selectOptions, $value, $label, $options, $template);
    	            break;
    	            
    	        case FormElement::Text:
    	        	echo $value;
    	        	break;
    	        	
    	        default:
    	            break;
    	    }
    	    $resultString = ob_get_contents();
    	    ob_end_clean();
    	    
    	    return $resultString;
    	}
    	
    	/**
    	 * Gets the full form contents
    	 * 
    	 * @return string
    	 */
    	private function GetContents()
    	{
    	    foreach ($this->elements as $elementName => $element)
    	    {
    	        $this->contentString .= $this->GetElementBlock($elementName);
    	    }
    	   
    	    return (!$this->disabled) ? HtmlHelper::GetTag('form', $this->formAttributes, $this->contentString) : HtmlHelper::GetTag('div', $this->formAttributes, $this->contentString);
    	}
    	
    	/**
    	 * Parses form data + metadata
    	 *
    	 * @param DbObject $data form object
    	 */
    	private function ParseFormData($data)
    	{
    		$this->metaData = $data->_metadata;
    		foreach ($this->metaData['indexes'] as $indexKey => $indexValue)
    		{
    			if (isset($indexValue['primary_key']) && $indexValue['primary_key'] === true)
    			{
    				$this->primaryKey[] = $indexKey;
    			}
    		}
    		
    		$this->data = $data;
    		$this->errors = (isset($this->data->_errors)) ? $this->data->_errors : null;
    		
    		unset($this->data->_metadata);
    		unset($this->data->_errors);
    	}
    	
    	/**
    	 * Parses DbObjects to select box compatible array
    	 *
    	 * @param array $dbObjects
    	 * @return array
    	 */
    	private function DbObjectsToArray($dbObjects)
    	{    		
    		//if array given
    		if (isset($dbObjects[0]))
    		{
    			if (is_array($dbObjects[0]))
    			{
    				return $dbObjects;
    			}
    			//if $key=>$value array provided
    			else if (!is_object($dbObjects[0]))
    			{
    				foreach ($dbObjects as $key => $value)
    				{
    					$resultArray[] = array('0' => $key, '1' => $value);
    				}
    				return $resultArray;
    			}
    		}
    		
    		$i = 0;
    		$result = array();
    		if (!empty($dbObjects))
    		{
	    		foreach ($dbObjects as $dbObject)
	    		{
	    			unset($dbObject->_metadata);
	    			$result[$i] = get_object_vars($dbObject);
	    			$i++;
	    		}
    		}

    		return $result;
    	}
    	
    	/**
    	 * Parses smart toolbar buttons
    	 *
    	 * @param array $buttons toolbar buttons
    	 * @return array
    	 */
    	private function ParseToolbarButtons(array $buttons)
    	{
    		$parsedButtons = array();
    		foreach ($buttons as $name => $button)
    		{
    			//parses primary key(-s) into string
    			$keys = '';
    			foreach ($this->primaryKey as $key)
    			{
    				$keys .= (isset($this->data->$key)) ? $this->data->$key.'/' : '';
    			}
    			
    			//parses the button URL
    			$button['url'] = StringUtils::GetContentFromTemplate($button['url'], array('pk' => $keys));
				
    			//translates the label if needed
    			$button['label'] = $this->Translate($button['label']);
    			
    			$parsedButtons[$name] = $button;
    		}
    		
    		return $parsedButtons;
    	}
    	
    	/**
    	 * Combines standard and custom toolbar buttons
    	 *
    	 * @param array $standardButtons standard buttons enumeration
    	 * @param array $customButtons custom buttons array
    	 * @return array all (combined) toolbar buttons
    	 */
    	private function CombineToolbarButtons(array $standardButtons = array(), array $customButtons = array())
    	{
    		$buttons = array();
    		foreach ($standardButtons as $name => $url)
    		{
    			switch ($name)
    			{
    				case 'add':
    					$buttons['add_button'] = array('label'=>'New', 'url'=>$url, 'image'=>IMAGES.'icon32add.png');
    					break;
    				case 'back':
    					$buttons['back_button'] = array('label'=>'Back', 'url'=>$url, 'image'=>IMAGES.'icon32back.png');
    					break;
    				case 'separator':
    					$buttons['separator_button'] = array('type'=>ToolbarItemType::Separator);
    					break;
    				case 'delete':
    					$buttons['delete_button'] = array('label'=>Language::Get('Delete'), 'url'=>$url, 'image'=>IMAGES.'icon32delete.png', 'html_attributes' => "id = '{$this->id}_button_delete' onclick = 'deleteURL = this.href; $(\"#{$this->id}_popup_delete\").dialog(\"open\"); return false; '");
    					
    					//delete confirmation popup
			    	    jQueryHelper::Dialog($this->id.'_popup_delete', array
			    	    	(
			    	    		'autoOpen' => 'false',
			    	    		'modal' => 'true',
			    	    		'resizable'=>'false',
			    	    		'title' => "'".Language::Get('Delete')."'",
			    	    	   	'buttons' => "
			    	    	   		{
										'".Language::Get('Delete')."': function() 
										{
											$(this).dialog('close');
											window.open(deleteURL, '_self');
										},
										".Language::Get('Cancel').": function()
										{
											$(this).dialog('close');
										}
									}
			    	    		"
			    	    	), Language::Get('Confirm delete').'?'
			    	    );
    					
    					break;
    				case 'list':
    					$buttons['list_button'] = array('label'=>'List', 'url'=>$url, 'image'=>IMAGES.'icon32list.png');
    					break;
    			}
    		}
    		
    		return array_merge($buttons, $customButtons);
    	}
    	
    	
    	/* FORM METHODS */
    	
    	/**
    	 * Initializes the form
    	 * 
    	 * @param string $action form action attribute
    	 * @param FormMethod $method form method attribute
    	 * @param array $attributes form html attributes
    	 */
    	public function Create($action, $method = FormMethod::Post, $attributes = array())
    	{
    		$attributes['id'] = (!isset($attributes['id'])) ? $this->id : $attributes['id'];
    	    $this->formAttributes = $attributes;
    	    $this->formAttributes['action'] = $action;
    	    $this->formAttributes['method'] = $method;
    	    
    	    //for AJAX form submit
			$this->formAttributes['onsubmit'] = (isset($this->formAttributes['onsubmit'])) ? $this->formAttributes['onsubmit'] : '';
			$this->formAttributes['onsubmit'] = ($method == FormMethod::AJAX) ? $this->formAttributes['onsubmit']." \$('#{$this->id} input:submit').fadeOut(); ".jQueryHelper::Post($action, $this->id, "function(data) {\$('#{$this->id}').parent().find('.formHeaderMessagePlaceholder').html(data); \$('#{$this->id} input:submit').fadeIn(); } ")." return false; " : $this->formAttributes['onsubmit'];
    	    
    	    return $this;
    	}

    	/**
    	 * Sets form header
    	 * 
    	 * @param string $text header text
    	 * @param string $template header template. If not set is taken from $this->headerTemplate
    	 */
    	public function Header($text, $template = '')
    	{
    	    $this->headerString = str_replace('{header}', $text, StringUtils::GetValue($template, $this->headerTemplate));
    	    
    	    return $this;
    	}
    	
    	/**
    	 * Sets form footer
    	 * 
    	 * @param string $text footer text
    	 * @param string $template footer template. If not set is taken from $this->footerTemplate
    	 */
    	public function Footer($text, $template = '')
    	{
    	    $this->footerString = str_replace('{footer}', $text, StringUtils::GetValue($template, $this->footerTemplate));
    	    
    	    return $this;
       	}

    	/**
    	 * Sets form message
    	 * 
    	 * @param string $text message text
    	 * @param string $template message template. If not set is taken from $this->messageTemplate
    	 */
    	public function Message($text, $template = '')
    	{
    	    $this->messageString = str_replace('{message}', $text, StringUtils::GetValue($template, $this->messageTemplate));
    	    
    	    return $this;
    	}
    	
    	/**
    	 * Adds form text element
    	 * 
    	 * @param string $text text text
    	 */
    	public function Text($text)
    	{
    	    $attributes['value'] = $text;
    	    $this->AddElement('text', mt_rand(1, 1000000), null, '', $attributes);
    	    
    	    return $this;
    	}
    	
    	/**
    	 * Sets form error
    	 * 
    	 * @param string $text error text
    	 * @param string $template error template. If not set is taken from $this->errorTemplate
    	 */
    	public function Error($text, $template = '')
    	{
    	    $this->errorString = (!empty($text)) ? str_replace('{error}', $text, StringUtils::GetValue($template, $this->errorTemplate)) : '';
    	    
    	    return $this;
    	}
    	
		/**
		 * Adds form toolbar
		 *
    	 * @param array $standardButtons standard buttons enumeration
    	 * @param array $customButtons custom buttons array
		 * @param string $id toolbar id
		 */
    	public function Toolbar(array $standardButtons = array(), array $customButtons = array(), $id = 'toolbar')
    	{
			$toolbar = new Toolbar();
			$toolbarSchema['name'] = $id;
			$toolbarSchema['html_attributes'] = " style = 'text-align: left; ' ";
			$buttons = $this->CombineToolbarButtons($standardButtons, $customButtons);
			$toolbarSchema['items'] = $this->ParseToolbarButtons($buttons);
			
			$this->toolbarString = $toolbar->Render($toolbarSchema);

			return $this;
    	}
    	
    	/**
    	 * Removes the given field from the current form
    	 * 
    	 * @param string $name field name
    	 */
    	public function RemoveField($name)
    	{
    	    unset($this->elements[$name]);
    	    
    	    return $this;
    	}
    	
    	/**
    	 * Renders the form
    	 */
    	public function Render()
    	{
    	    return StringUtils::GetContentFromTemplate($this->template, array
    	        (
    	            'toolbar' => $this->toolbarString,
    	            'header' => $this->headerString,
    	        	'message' => $this->messageString,
    	            'error' => $this->errorString,
    	            'form' => $this->GetContents(),
    	            'footer' => $this->footerString,
    	        ));
    	}

    	/**
    	 * Displays the form
    	 */
    	public function Display()
    	{
    	    echo $this->Render();
    	}
    	
    	
    	/* ELEMENT METHODS */
    	
    	/**
    	 * Adds input element
    	 * 
    	 * @param string $name input name
    	 * @param InputType $type input type
    	 * @param array $options field options
    	 * @param array $attributes field attributes
    	 */
    	public function Input($name, $type = '', $options = array(), $attributes = array())
    	{
    	    $attributes['type'] = (empty($type)) ? InputType::Text : $type;
    	    $this->AddElement('input', $name, $options, '', $attributes);
    	    
    	    return $this;
    	}
    	
        /**
    	 * Adds input text element
    	 * 
    	 * @param string $name field name
    	 * @param array $options field options
    	 * @param array $attributes field attributes
    	 */
    	public function Textfield($name, $options = array(), $attributes = array())
    	{
    		$attributes['type'] = InputType::Text;
    	    $this->AddElement('input', $name, $options, '', $attributes);
    	    
    	    return $this;
    	}   

        /**
    	 * Adds input date element
    	 * 
    	 * @param string $name field name
    	 * @param array $options field options
    	 * @param array $attributes field attributes
    	 */
    	public function Date($name, $options = array(), $attributes = array())
    	{
    		$attributes['type'] = InputType::Text;
    		$attributes['autocomplete'] = 'off';
    		
    		
    	    $this->AddElement('input', $name, $options, '', $attributes);

    	    //jQuery calendar
    	    $options['jQuery'] = (isset($options['jQuery'])) ? $options['jQuery'] : array();
    	    $jQueryOptions = array_merge($options['jQuery'], array('dateFormat' => '"'.str_replace('d', 'dd', str_replace('m', 'mm', str_replace('Y', 'yy', Config::$general['date_format']))).'"'));
    		jQueryHelper::DatePicker($this->GetFieldId($name, $attributes), $jQueryOptions);
    	
    		return $this;
    	}    	
    	
        /**
    	 * Adds input datetime element
    	 * 
    	 * @param string $name field name
    	 * @param array $options field options
    	 * @param array $attributes field attributes
    	 */
    	public function DateTime($name, $options = array(), $attributes = array())
    	{
    		$attributes['type'] = InputType::Text;
    	    $this->AddElement('input', $name, $options, '', $attributes);

    	    //jQuery calendar
    	    $options['jQuery'] = (isset($options['jQuery'])) ? $options['jQuery'] : array();
    	    $jQueryOptions = array_merge($options['jQuery'], array('dateFormat' => '"'.str_replace('d', 'dd', str_replace('m', 'mm', str_replace('Y', 'yy', Config::$general['date_format']))).'"'));
    		jQueryHelper::DateTimePicker($this->GetFieldId($name, $attributes), $jQueryOptions);
    	
    		return $this;
    	}    	
    	
        /**
    	 * Adds input hidden element
    	 * 
    	 * @param string $name field name
    	 * @param array $attributes field attributes
    	 */
    	public function Hidden($name, $attributes = array())
    	{
    		$attributes['type'] = InputType::Hidden;
    	    $this->AddElement('input', $name, array(), '', $attributes);
    	    
    	    return $this;
    	}    	

        /**
    	 * Adds input password element
    	 * 
    	 * @param string $name field name
    	 * @param array $options field options
    	 * @param array $attributes field attributes
    	 */
    	public function Password($name, $options = array(), $attributes = array())
    	{
    		$attributes['type'] = InputType::Password;
    		$attributes['value'] = '';
    		$attributes['autocomplete'] = 'off';
    		$this->AddElement('input', $name, $options, '', $attributes);
    		
    		return $this;
    	}    	

    	/**
    	 * Adds checkbox element
    	 * 
    	 * @param string $name field name
    	 * @param array $options field options
    	 * @param array $attributes field attributes
    	 */
		public function Checkbox($name, $options = array(), $attributes = array())
    	{
    	    $attributes['type'] = InputType::Checkbox;
    	    $this->AddElement('input', $name, $options, '', $attributes);
    	    
    	    return $this;
    	}
    	
    	/**
    	 * Adds textarea element
    	 * 
    	 * @param string $name field name
    	 * @param array $options field options
    	 * @param array $attributes field attributes
    	 */
    	public function Textarea($name, $options = array(), $attributes = array())
    	{
    	    $this->AddElement('textarea', $name, $options, '', $attributes);
    	    
    	    return $this;
    	}
    	
    	/**
    	 * Adds select element
    	 * 
    	 * @param string $name field name
    	 * @param array $options field options
    	 * @param array $attributes field attributes
    	 */
    	public function Select($name, $options = array(), $attributes = array())
    	{
    		$options['options'] = $this->DbObjectsToArray($options['options']);
    	    $this->AddElement('select', $name, $options, '', $attributes);
    	    
    	    return $this;
    	}
    	
        /**
         * Submit button block
         * 
         * @param string $name field name
         * @param array $options options
         * @param array $attributes field attributes
         * 
         * @return FormHelper
         */
        public function Submit($value, $options = array(), $attributes = array())
    	{
    	    $attributes['type'] = (!isset($attributes['type'])) ? InputType::Submit : $attributes['type'];
    	    if ($attributes['type'] == InputType::Image)
    	    {
    	    	$attributes['src'] = $value;
    	    	$attributes['alt'] = '';
    	    	$value = '';
    	    }
    	    else 
    	    {
    	    	$attributes['value'] = $this->Translate($value);
    	    }

    		$options['template'] = (!isset($options['template'])) ? $this->buttonTemplate : $options['template'];
    	    
    	    $name = (isset($options['name'])) ? $options['name'] : 'submit';
    	    $options['label'] = false;
    	    $this->AddElement('input', $name, $options, '', $attributes);
    	    
    	    return $this;
    	}
    	
    	/**
    	 * Reset button block
    	 *
    	 * @param string $value button text
    	 * @param string $url reset url
    	 * @param array $options field options
    	 * @param array $attributes field attributes
    	 * 
    	 * @return FormHelper
    	 */
    	public function Cancel($value, $url, $options = array(), $attributes = array())
    	{
    		$attributes['type'] = (!isset($attributes['type'])) ? InputType::Reset : $attributes['type'];
    		$attributes['onclick'] = (!isset($attributes['onclick'])) ? "window.location = '$url'" : $attributes['onclick'];
    		$options['template'] = (!isset($options['template'])) ? $this->buttonTemplate : $options['template'];
    		$attributes['value'] = $this->Translate($value);
    		
    	    $name = (isset($options['name'])) ? $options['name'] : 'cancel';
    	    $options['label'] = false;
    	    $this->AddElement('input', $name, $options, '', $attributes);
    	    
    	    return $this;
    	}
    	
    	
    	/* SECURITY */
    	
    	/**
    	 * Sets the access level for the given element
    	 * 
    	 * @param string|array $names field name or field names' array 
    	 * @param AccessType $type access type
    	 */
    	public function SetAccess($names, $type)
    	{
    		if (is_array($names))
    		{
	    		foreach ($names as $name)
	    		{
		    	    $this->elements[$name]['access'] = $type;
		    	    $this->elements[$name]['attributes'][$type] = $type;
	    		}
    		}
    		else if ($names === '*')
    		{
    			foreach ($this->elements as $key=>$value)
    			{
    				if (!($value['attributes']['type'] == 'reset'))
    				{
    					$this->elements[$key]['access'] = $type;
    					$this->elements[$key]['attributes'][$type] = $type;
    				}
    			}
    		}
    		else 
    		{
		    	$this->elements[$names]['access'] = $type;
		    	$this->elements[$names]['attributes'][$type] = $type;
    		}
    	    
    	    return $this;
    	}

    }
?>